#ifndef NE_STL_INCLUDENE_STL_MEMORY_H
#define NE_STL_INCLUDENE_STL_MEMORY_H

#include "ne_stl_atomic.h"
#include "ne_stl_build.h"
#include "ne_stl_spinlock.h"
namespace nstd {

template <class TElement>
using element_malloc_fun_t = TElement* (*)(std::size_t /*count*/);

template <class TElement>
using element_delete_fun_t = void (*)(TElement*&);

struct memory {
    template <class TElement>
    static TElement* safe_malloc_container_element(std::size_t count) {
        return new TElement[count]();
    }
    template <class TElement>
    static void safe_delete_container_element(TElement*& element_ptr) {
        if (element_ptr != nullptr) {
            delete[] element_ptr;
            element_ptr = nullptr;
        }
    }
    template <class TObject, class... TArgs>
    static TObject* safe_new(TArgs... args) {
        return new TObject(args...);
    }
    template <class TObject>
    static void safe_delete(TObject*& object_ptr) {
        if (object_ptr != nullptr) {
            delete object_ptr;
            object_ptr = nullptr;
        }
    }
    template <typename TObject, typename... TArgs>
    static TObject* new_obj(TArgs... args) {
        TObject* ret = (TObject*)malloc(sizeof(TObject));
        if (ret == nullptr)
            return nullptr;
        new (ret) TObject(args...);
        return ret;
    }
    template <typename TObject>
    static bool delete_obj(TObject*& object) {
        if (object == nullptr)
            return false;
        char* src = (char*)object;
        object->~TObject();
        free(src);
        object = nullptr;
        return true;
    }
};

template <class _Ty>
struct default_delete {
    typedef default_delete<_Ty> _Myt;
    default_delete() {}
    template <class _Ty2, class = typename std::enable_if<std::is_convertible<_Ty2*, _Ty*>::value, void>::type>
    default_delete(const default_delete<_Ty2>&) {}
    void operator()(_Ty* _Ptr) const {
        static_assert(0 < sizeof(_Ty), "can't delete an incomplete type");
        delete _Ptr;
    }
};
enum class EM_Byte_Endian_Order {
    big_endian = 0,
    little_endian = 1,
};
struct byte_endian_order {
    static inline EM_Byte_Endian_Order value() {
        static atomic_bool _once_flag{false};
        static spinlock _lock;
        static EM_Byte_Endian_Order order{EM_Byte_Endian_Order::little_endian};
        if (!_once_flag) {
            lock_guard auto_lock(_lock);
            if (!_once_flag) {
                static uint16_t param = 0x0001;
                if (*(uint8_t*)(&param) == 0x01)
                    order = EM_Byte_Endian_Order::little_endian;
                else
                    order = EM_Byte_Endian_Order::big_endian;
                _once_flag = true;
            }
        }
        return order;
    }
    static inline bool same_to_host(EM_Byte_Endian_Order order) { return order == value(); }
    static inline bool is_little_endian() { return value() == EM_Byte_Endian_Order::little_endian; }
};
}  // namespace nstd

#endif  // !NE_STL_INCLUDENE_STL_MEMORY_H